package datos;

import java.util.Set;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.ListIterator;


/* Mi cosa favorita de Java es que, al tener tipado estatico, es muy seguro */
public class Dato {
    public static class Builder implements IBuilder<String, Dato> {
        private List<Atributo<Object>> declaracionAtributos;
        private List<Object> atributos;
        
        private ListIterator<Atributo<Object>> siguienteDeclaracion;
        private ListIterator<Object> siguienteAtributo;

        public Builder(List<Atributo<Object>> declaracionAtributos) {
            this.declaracionAtributos = declaracionAtributos;
            this.reset();
        }

        @Override
        public void reset() {
            this.atributos = new ArrayList<Object>(declaracionAtributos.size());
            this.siguienteDeclaracion = this.declaracionAtributos.listIterator();
            this.siguienteAtributo = this.atributos.listIterator();
        }

        @Override
        public void add(String s) {
            if (!this.siguienteDeclaracion.hasNext()) {
                throw new RuntimeException("Record with invalid number of attributes");
            }
            Atributo<Object> declaracion = this.siguienteDeclaracion.next();
            atributos.add(declaracion.readDato(s));
        }

        @Override
        public Dato finish() {
            if (this.siguienteDeclaracion.hasNext()) {
                /* Excepcion */
                return null;
            }
            Dato d = new Dato();
            for (int i = 0; i < this.declaracionAtributos.size(); i++) {
                Atributo<Object> atributo = (Atributo<Object>)this.declaracionAtributos.get(i);
                Object valor = this.atributos.get(i);
                d.setAtributo(atributo, valor);
            }
            this.reset(); 
            return d;
        }
    }

    private Map<Atributo<?>, Object> atributos;

    public Dato() {
        this.atributos = new HashMap<Atributo<?>, Object>();
    }

    public <T> void setAtributo(Atributo<T> atributo, T valor) {
        this.atributos.put(atributo, valor);
    }
    public <T> T getAtributo(Atributo<T> atributo) throws ClassCastException {
        return (T)this.atributos.get(atributo);
    }

    public Set<Atributo<?>> getAtributos() {
        return this.atributos.keySet();
    }
    
    @Override
    public String toString()
    {
    	String result = "Dato[";
    	for(Atributo<?> atributo: getAtributos())
    	{
    		result += atributo.getNombre() + "=" + this.getAtributo(atributo);
    	}
    	
    	result += "]";
    	
    	return result;
    }
}
